#include <map>
#include <vector>
#include <iostream>

#include "auto_decltype.h"

class A {
public:
    static int get(void) {
        return 0;
    }
};

class B {
public:
    static const char* get(void) {
        return "0";
    }
};


template<class T>
void func(void) {
    auto val = T::get();
    // ...
}

void auto_keyword(void) {
    auto     x    = 0;                   // x自动推导为int类型;
    auto     pi   = new auto(1);         // pi自动推导为int*类型, 可用于new关键字;
    delete   pi;

    const auto *y = &x, u = 6;           // auto 为 int, y为const int *；
    // const auto *y = &x, u = 6;        // error: auto 产生歧义性
    static auto v = 0.0;                 // auto 为 double

    // TODO: 特别注意
    // 使用auto自动推导的变量必须马上初始化, 以让编译器知道它的类型
    // auto s;                           // error: 无法判断类型

    ///////////////////////////////////////////////////////////////
    auto  *a = &x;                       // a -> int*, auto -> int
    auto   b = &x;                       // b -> int*, auto -> int

    auto  &c = x;                        // c -> int&, auto -> int
    auto   d = x;                        // d -> int,  auto -> int

    const auto   e = x;                  // e -> const int

    // TODO: 特别注意
    // f的结果，可以知道，const被抛弃了,形成了non-const的int
    auto         f = e;                  // f -> int

    const auto&  g = x;                  // g -> const int&;

    // TODO: 特别注意
    // auto与引用结合时, 自动推导会保留const关键字
    auto&        h = g;                  // h -> const int&;

    // TODO: 总结
    /**
    **  1. 不声明为指针或引用时，auto推导会自动抛弃引用和cv限定符
    **  2. 当声明为指针或引用时, auto会保存初始化表达式cv限定符;
    **  3. auto不能用于函数的参数;
    **  4. auto不能用于非静态成员变量;
    **  5. auto无法定义数组;
    **  6. auto无法推导模板参数; 
    */

    // auto 典型应用-1
    std::map<int, double> stu;
    // for (std::map<int, double>::iterator it = stu.begin(); it != stu.end(); ++it) {
    // }
    for (auto it = stu.begin(); it != stu.end(); ++it) {
        // code here
    }

    // auto 典型应用-2
    func<A>();

    return 0;
}


// template<class ContainerT>
// class Foo {
//     typename ContainerT::iterator it;
// public:
//     void func(ContainerT& container) {
//         it = container.begin();
//     }
// };

// 如果传入的容器是一个const容器，则Foo的func函数会使用const_iterator
// C++98/03的规范下，只能进行模板特化
// template<class ContainerT>
// class Foo<const ContainerT> {
//     typename ContainerT::const_iterator it;
// public:
//     void func(const ContainerT& container) {
//         it = container.begin();
//     }
// };

// C++ 11的实现
template<class ContainerT>
class Foo {
    // 使用decltype进行类型推导
    decltype(ContainerT().begin()) it;
public:
    void func(ContainerT& container) {
        it = container.begin();
    }
};

// 返回类型后置
template<typename T, typename U>
auto add(T t, U u) -> decltype(t+u) {
    return t+u;
}


void decltype_keyword(void) {
    int           x    = 1;
    decltype(x)   y    = 1;               // y -> int, decltype用于推导表达式的类型
    decltype(x+y) z    = 4;               // z -> int, decltype用于推导表达式的类型

    const int&    i    = x;
    // TODO: decltype 可以精确推导出引用和cv表达式，而不像auto那样会在有时丢弃
    decltype(i)   j    = y;               // j -> const int&


    // decltype 典型应用-1


    // decltype 典型应用-2

    return 0;
}
